package com.wei.czz.common.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-10-02 11:03:00
 * className: TimeUtils 日期工具类
 * version: 1.0
 * description:
 */
public class TimeUtils {

    /**
     * 日期格式化对象
     */
    public static final DateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 获取系统时间所在日的开始时间（零点零分零秒）
     * 如：
     *  今天是2021-09-05，则获取的结果为：2021-09-05 00:00:00（格式化显示结果）
     *  今天是2021-10-07，则获取的结果为：2021-10-07 00:00:00（格式化显示结果）
     * @return 时间对象
     */
    public static Date startToDay() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    /**
     * 获取今日结束时间（23点59分59秒999毫秒）
     * 如：
     *  今天是2021-10-10，则获取的结果为：2021-10-10 23:59:59（格式化显示结果）
     *  今天是2021-10-12，则获取的结果为：2021-10-12 23:59:59（格式化显示结果）
     */
    public static Date endToDay() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 59);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 59);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 999);

        return calendar.getTime();
    }

    /**
     * 获取下一天的开始时间（零点零分零秒）
     * 如：
     *  今天是2021-09-01，则获取的结果为：2021-09-02 00:00:00（格式化显示结果）
     *  今天是2021-10-07，则获取的结果为：2021-10-08 00:00:00（格式化显示结果）
     *  今天是2021-10-31，则获取的结果为：2021-11-01 00:00:00（格式化显示结果）
     * @return 时间对象
     */
    public static Date nextTodayStart() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);
        // 天数增加一天
        calendar.add(Calendar.DAY_OF_MONTH, 1);

        return calendar.getTime();
    }

    /**
     * 获取系统时间所在月的开始时间（一日零点零分零秒）
     * 如：
     *   今天是2021-10-01，则获取的结果为：2021-10-01 00:00:00（格式化显示结果）
     *   今天是2021-10-30，则获取的结果为：2021-10-01 00:00:00（格式化显示结果）
     *   今天是2021-11-20，则获取的结果为：2021-11-01 00:00:00（格式化显示结果）
     */
    public static Date firstDayOnThisMonth() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);
        // 设置天数值（几号）
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        return calendar.getTime();
    }

    /**
     * 获取系统时间所在月的结束时间（最后一日23点59分59秒）
     * 如：
     *  今天是2022-01-01，则获取的结果为：2021-01-31 23:59:59（格式化显示结果）
     *  今天是2022-02-03，则获取的结果为：2021-02-28 23:59:59（格式化显示结果）
     *  今天是2022-03-28，则获取的结果为：2021-03-31 23:59:59（格式化显示结果）
     * @return 日期对象
     */
    public static Date endTimeOnThisMonth() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);
        // 设置天数值（几号）
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 时间增加一个月
        calendar.add(Calendar.MONTH, 1);
        // 时间减少一天
        calendar.add(Calendar.DAY_OF_MONTH, -1);

        return calendar.getTime();
    }

    /**
     * 获取系统时间所在年的开始时间（一月一日零点零分零秒）
     * 如：
     *   今天是2022-01-01，则获取的结果为：2022-01-01 00:00:00（格式化显示结果）
     *   今天是2022-02-20，则获取的结果为：2022-01-01 00:00:00（格式化显示结果）
     *   今天是2022-03-02，则获取的结果为：2022-01-01 00:00:00（格式化显示结果）
     */
    public static Date firstDayOnThisYear() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置月数值（几月）
        calendar.set(Calendar.MONTH, 0);
        // 设置天数值（几号）
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    /**
     * 根据参数时间对象，获取参数时间’所在日‘的’前一日‘的开始时间和结束时间
     * 如：
     *  今天是2022-02-01，则获取的结果为：2022-01-31 00:00:00、2022-01-31 23:59:59（格式化显示结果）
     *  今天是2022-03-01，则获取的结果为：2022-02-28 00:00:00、2022-02-28 23:59:59（格式化显示结果）
     *  今天是2022-04-25，则获取的结果为：2022-04-24 00:00:00、2022-04-24 23:59:59（格式化显示结果）
     * @param date 时间对象
     * @return 封装两个时间对象的列表[下标0-开始时间 下标1-结束时间]
     */
    public static Date[] getPreDayByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);
        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 时间减少一天
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        // 获取开始时间
        Date startTime = calendar.getTime();

        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        // 获取结束时间
        Date endTime = calendar.getTime();

        return new Date[] { startTime, endTime };
    }

    /**
     * 根据参数时间对象，获取参数时间’所在月‘的’上一月‘的开始时间和结束时间
     * 如：
     *  今天是2022-02-01，则获取的结果为：2022-01-01 00:00:00、2022-01-31 23:59:59（格式化显示结果）
     *  今天是2022-03-01，则获取的结果为：2022-02-01 00:00:00、2022-02-28 23:59:59（格式化显示结果）
     *  今天是2022-04-25，则获取的结果为：2022-03-01 00:00:00、2022-03-31 23:59:59（格式化显示结果）
     * @param date 时间对象
     * @return 封装两个时间对象的列表[下标0-开始时间 下标1-结束时间]
     */
    public static Date[] getPreMonthByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);
        // 设置日期为1号
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 获取开始时间
        Date startTime = calendar.getTime();

        // 时间增加一个月并减少一天，得到所在月的最后一天
        calendar.add(Calendar.MONTH, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);

        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        // 获取结束时间
        Date endTime = calendar.getTime();

        return new Date[] { startTime, endTime };
    }

    /**
     * 根据参数时间对象，获取参数时间’所在年‘的’上一年‘的开始时间和结束时间
     * 如：
     *  今天是2020-02-01，则获取的结果为：2019-01-01 00:00:00、2019-12-31 23:59:59（格式化显示结果）
     *  今天是2021-03-01，则获取的结果为：2020-01-01 00:00:00、2020-12-31 23:59:59（格式化显示结果）
     *  今天是2022-04-25，则获取的结果为：2021-01-01 00:00:00、2021-12-31 23:59:59（格式化显示结果）
     * @param date 时间对象
     * @return 封装两个时间对象的列表[下标0-上一年开始时间 下标1-上一年结束时间]
     */
    public static Date[] getPreYearByDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);
        // 设置日期为1月1号
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 获取开始时间
        Date startTime = calendar.getTime();

        // 时间增加一年并减少一天，得到所在年的最后一天
        calendar.add(Calendar.YEAR, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);

        // 设置小时、分钟、秒和毫秒数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        // 获取结束时间
        Date endTime = calendar.getTime();

        return new Date[] { startTime, endTime };
    }

    /**
     * 日期对象格式化（yyyy-MM-dd HH:mm:ss）
     * @param date 日期对象
     * @return 格式化对象
     */
    public static String format(Date date) {
        return yyyyMMddHHmmss.format(date);
    }

    /**
     * 字符串日期（yyyy-MM-dd HH:mm:ss）格式化成日期对象
     * @param date 字符串日期
     * @return 日期对象
     * @throws ParseException 异常类型
     */
    public static Date parse(String date) throws ParseException {
        return yyyyMMddHHmmss.parse(date);
    }

    /**
     * 根据日期对象，获取日期对象当天的开始时间
     * @param date 日期对象
     * @return 当天的开始时间
     */
    public static Date getStartDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);
        // 设置小时、分钟、秒值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    /**
     * 根据日期对象，获取日期对象当天的结束时间
     * @param date 日期对象
     * @return 当天的结束时间
     */
    public static Date getEndDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);
        // 设置小时、分钟、秒值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);

        return calendar.getTime();
    }

    /**
     * 根据日期对象，获取日期对象’所在月‘的开始时间
     * @param date 日期对象
     * @return 所在月的开始时间
     */
    public static Date getMonthStartDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        // 设置基准时间
        calendar.setTime(date);

        // 设置日期为1号
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 设置小时、分钟、秒、毫秒值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    /**
     * 获取当前时间’所在日‘的开始时间和结束时间
     * 如：
     *  今天是2023-12-01，则获取的结果为：2023-12-01 00:00:00、2023-12-01 23:59:59（格式化显示结果）
     *  今天是2023-11-06，则获取的结果为：2023-11-06 00:00:00、2023-11-06 23:59:59（格式化显示结果）
     *  今天是2022-12-06，则获取的结果为：2022-12-06 00:00:00、2022-12-06 23:59:59（格式化显示结果）
     * @return 日期对象数组
     */
    public static Date[] getCurrentDates() {
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);

        Date startDate = calendar.getTime();

        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 59);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 59);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 999);

        Date endDate = calendar.getTime();

        return new Date[] { startDate, endDate };
    }

    /**
     * 获取当前时间’所在月‘的开始时间和结束时间
     * 如：
     *  今天是2023-12-01，则获取的结果为：2023-12-01 00:00:00、2023-12-01 23:59:59（格式化显示结果）
     *  今天是2023-11-06，则获取的结果为：2023-11-06 00:00:00、2023-11-06 23:59:59（格式化显示结果）
     *  今天是2022-12-06，则获取的结果为：2022-12-06 00:00:00、2022-12-06 23:59:59（格式化显示结果）
     * @return 日期对象数组
     */
    public static Date[] getCurrentMonthDates() {
        // 获取时间对应的日历对象
        Calendar calendar = Calendar.getInstance();
        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 0);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 0);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 0);
        // 设置天数值（几号）
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        Date startDate = calendar.getTime();

        // 日期增加一个月
        calendar.add(Calendar.MONTH, 1);
        // 时间减少一天（回到这个月的月底）
        calendar.add(Calendar.DAY_OF_MONTH, -1);

        // 设置小时数值
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        // 设置分钟数值
        calendar.set(Calendar.MINUTE, 59);
        // 设置秒数数值
        calendar.set(Calendar.SECOND, 59);
        // 设置毫秒数值
        calendar.set(Calendar.MILLISECOND, 999);

        Date endDate = calendar.getTime();

        return new Date[] { startDate, endDate };
    }

    /**
     * 时间戳转时间对象
     * @param timestamp 时间戳
     * @return 年月日对象
     */
    public static LocalDate toLocalDate(Long timestamp) {
        // 转换为LocalDate
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 时间戳转时间对象
     * @param date 时间对象
     * @return 年月日对象
     */
    public static LocalDate toLocalDate(Date date) {
        // 转换为LocalDate
        return toLocalDate(date.getTime());
    }

    /**
     * 时间戳转时间对象
     * @param timestamp 时间戳
     * @return 年月日对象
     */
    public static LocalDateTime toLocalDateTime(Long timestamp) {
        // 转换为LocalDateTime
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 时间戳转时间对象
     * @param date 时间对象
     * @return 年月日对象
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        // 转换为LocalDateTime
        return toLocalDateTime(date.getTime());
    }

    /**
     * 时间对象转时间戳
     * @param localDateTime 时间对象
     * @return 时间戳
     */
    public static long toTimestamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 时间对象转时间戳
     * @param localDateTime 时间对象
     * @return 时间对象
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return new Date(toTimestamp(localDateTime));
    }

    /**
     * 时间对象转时间戳
     * @param localDate 时间对象
     * @return 时间戳
     */
    public static long toTimestamp(LocalDate localDate) {
        return localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 时间对象转时间戳
     * @param localDate 时间对象
     * @return 时间对象
     */
    public static Date toDate(LocalDate localDate) {
        return new Date(toTimestamp(localDate));
    }

    /**
     * 两个日期相差的天数
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 相差的天数
     */
    public static long betweenDays(Date startDate, Date endDate) {
        if (startDate.after(endDate)) {
            Date t = startDate;
            startDate = endDate;
            endDate = t;
        }
        LocalDateTime start = toLocalDateTime(startDate);
        LocalDateTime end = toLocalDateTime(endDate);
        // 计算间隔天数
        return ChronoUnit.DAYS.between(start, end);
    }

    /**
     * 两个日期相差的月数
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 相差的月数
     */
    public static long betweenMonths(Date startDate, Date endDate) {
        if (startDate.after(endDate)) {
            Date t = startDate;
            startDate = endDate;
            endDate = t;
        }
        LocalDateTime start = toLocalDateTime(startDate);
        LocalDateTime end = toLocalDateTime(endDate);

        // 计算间隔月数
        return ChronoUnit.MONTHS.between(start, end);
    }

}
